package com.xhl.consul.tool.controller;

import com.alibaba.fastjson.JSON;
import com.commons.tools.utils.Result;
import com.xhl.common.util.MakeRSAUtil;
import com.xhl.consul.tool.entity.User;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.TextCodec;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.*;
import java.util.*;

/**
 * @Author CazCen
 * @Date 2021/11/30 19:39
 */
@Api(tags = "Jwt测试")
@RestController
@RequestMapping("/test/jwt")
@Slf4j
public class JwtOfController {

    Map<String,String> mapTokenToSign = new HashMap<String,String>();

    // 和网关相同的,这样token就可以再网关通过
    private String JWT_SECRET = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr5OgTq+vQOKbjQhtivaUSOm0YZ8BA0GVHroITVrLqa4EIS1S3e6YSnZ3S0UIlzJCni/nzQ9YCC8DxYhCtmdnOUOC7wsrKXMBVRpTI6A/WL8lj9Pr4zXEaAhmhb+3W7dJYOBnmV9ky3i6bfqN1S7mGVCxNd4JAdrn7SRw8JYfl+aBAX56XgoXB0Q1N3zIr8PIrmL85ZFN6V00QwY3fCnorhG/UirgCPMdeXzoR7Z/8x8UHeeuHqZQ2SVMliIER5VWXN+rgavNtvHPy9T2UgjuYzJp0XkjYaFpXhIbQzTgwrQuP73pwlAQOfOPfgXdGQXqnFkrggaQZz7+vc2QZzHY/QIDAQAB";




    // 将用户信息经过RSA算法加密之后，存储到jwt的claim中作为token的一部分
    KeyPair keyPair = MakeRSAUtil.getKeyPair();
    PrivateKey aPrivate = keyPair.getPrivate();
    PublicKey aPublic = keyPair.getPublic();


    @PostMapping("/token")
    @ApiOperation("获取Token测试")
    public Result<String> getToken(@RequestBody User user, HttpServletResponse response){
        log.info("用户请求登录 : user:{}",user);

        // 使用公钥将 user 解密,加密之后，不需要解密了,所以这里其实不需要使用到私钥
        String jsonUser = JSON.toJSONString(user);
        byte[] bytes = null;
        try {
            bytes = MakeRSAUtil.encryptByPublicKey(jsonUser.getBytes(), aPublic.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error(e.getMessage());
        }

        JwtBuilder builder = Jwts.builder();
        // 把经过加密之后的User信息放到claim,这样就安全了
        // 因为一般claim中是不能存放敏感信息的,如果将敏感信息加密之后再存储，是不是就可以了呢
        JwtBuilder jwtBuilder = builder
                .claim("authorization", bytes)
                .claim("userName","cazcen")
                // 设置秘钥
                .signWith(SignatureAlgorithm.HS256, TextCodec.BASE64.encode(JWT_SECRET))
                .setIssuedAt(new Date(System.currentTimeMillis()))
                // 设置过期时间是30分钟
                .setExpiration(new Date(System.currentTimeMillis() + 60*1000*30));

        String compactToken = jwtBuilder.compact();

        response.setHeader("token",compactToken);

        log.info("user:{}; compactToken:{}",user,compactToken);


        log.info("mapTokenToSign:{}",mapTokenToSign);

        return Result.ok(compactToken);
    }


    @PostMapping("/check")
    @ApiOperation("校验token")
    public Result checkToken(HttpServletRequest request,HttpServletResponse response){

        String strErrorMsg = "";
        String token = request.getHeader("token");

        try {

            // 验证
            Jwt parse = Jwts.parser().setSigningKey(TextCodec.BASE64.encode(JWT_SECRET)).parse(token);


            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(TextCodec.BASE64.encode(JWT_SECRET)).parseClaimsJws(token);

            Claims body = claimsJws.getBody();


            Object userName = body.get("userName");

            Object authorization = body.get("authorization");


            log.info("parse:{}",parse);

            log.info("parse:{}",parse.getBody());



            return Result.ok();
        }catch (ExpiredJwtException e){
            log.info("checkToken ExpiredJwtException ",e.getMessage());
            strErrorMsg = e.getMessage();
            e.printStackTrace();
        }catch (Exception e){
            log.info("checkToken Exception ",e.getMessage());
            strErrorMsg = e.getMessage();
            log.info(e.getMessage());
            e.printStackTrace();
        }

        mapTokenToSign.remove(token);



        return Result.error(strErrorMsg);



    }

}
